package com.boot.persistence;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.boot.cache.redis.RedisCache;
import com.boot.cache.redis.serializer.JacksonRedisSerializer;
import com.boot.cache.redis.serializer.NamedRedisKeySerializer;
import com.boot.cache.redis.serializer.UnSupportedSerializer;
import com.boot.persistence.condition.QueryCondition;
import com.boot.persistence.mapper.IMapper;
import com.boot.persistence.model.BaseModel;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.io.Serializable;

/**
 * @author 霜寒 <1621856595@qq.com>
 * @description Redis缓存层
 * @date 2023/2/5 16:13
 **/
public abstract class RedisCacheServiceImpl<Id extends Serializable, T extends BaseModel<Id>, Mapper extends IMapper<T>> extends CacheServiceImpl<Id, T, Mapper> {

    protected final ObjectMapper om;
    protected final String prefix;
    protected String delimiter;

    public RedisCacheServiceImpl(Mapper mapper, RedisConnectionFactory redisConnectionFactory, ObjectMapper om, String prefix) {
        this(mapper, redisConnectionFactory, om, prefix, NamedRedisKeySerializer.DELIMITER, true, false);
    }

    protected RedisCacheServiceImpl(Mapper mapper, RedisConnectionFactory redisConnectionFactory, ObjectMapper om,
                                    String prefix, String delimiter, boolean isCacheModel, boolean isCachePage) {
        super(mapper, isCacheModel ? new RedisCache<>(redisConnectionFactory, om, new UnSupportedSerializer<>(), new UnSupportedSerializer<>()) : null,
                isCachePage ? new RedisCache<>(redisConnectionFactory, om, new UnSupportedSerializer<>(), new UnSupportedSerializer<>()) : null);
        this.om = om;
        if (prefix.endsWith(delimiter)) {
            prefix = prefix.substring(0, prefix.length() - 1);
        }
        this.prefix = prefix;
        this.delimiter = delimiter;
        if (isCacheModel) {
            RedisCache<Id, T> modelCache = (RedisCache<Id, T>) this.getModelCache();
            modelCache.getRedisTemplate().setKeySerializer(getModelKeySerializer());
            modelCache.getRedisTemplate().setValueSerializer(getModelValueSerializer());
        }
        if (isCachePage) {
            RedisCache<QueryCondition<Id, T>, IPage<T>> pageCache = (RedisCache<QueryCondition<Id, T>, IPage<T>>) this.getPageCache();
            pageCache.getRedisTemplate().setKeySerializer(getPageKeySerializer());
            pageCache.getRedisTemplate().setValueSerializer(getPageValueSerializer());
        }
    }

    public RedisSerializer<Id> getModelKeySerializer() {
        return new NamedRedisKeySerializer<>(new JacksonRedisSerializer<>(om, super.getIdClass()), prefix, delimiter);
    }

    public RedisSerializer<T> getModelValueSerializer() {
        return new JacksonRedisSerializer<>(om, super.getModelClass());
    }

    public RedisSerializer<Id> getPageKeySerializer() {
        JavaType pageKeyType = om.getTypeFactory().constructParametricType(QueryCondition.class, getIdClass(), getModelClass());
        return new NamedRedisKeySerializer<>(new JacksonRedisSerializer<>(om, pageKeyType), "Page" + delimiter + prefix, delimiter);
    }

    public RedisSerializer<T> getPageValueSerializer() {
        JavaType pageValueType = om.getTypeFactory().constructParametricType(Page.class, getModelClass());
        return new JacksonRedisSerializer<>(om, pageValueType);
    }
}
